/*
 * @CopyRight:
 * FISCO-BCOS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FISCO-BCOS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FISCO-BCOS.  If not, see <http://www.gnu.org/licenses/>
 * (c) 2016-2018 fisco-dev contributors.
 */
/** @file test_PaillierPrecompiled.cpp
 *  @author shawnhe
 *  @date 20190813
 */

#include "Common.h"
#include <libblockverifier/ExecutiveContextFactory.h>
#include <libethcore/ABI.h>
#include <libprecompiled/extension/PaillierPrecompiled.h>
#include <boost/lexical_cast.hpp>
#include <boost/test/unit_test.hpp>

using namespace dev;
using namespace dev::blockverifier;
using namespace dev::precompiled;

namespace test_PaillierPrecompiled
{
struct PaillierPrecompiledFixture
{
    PaillierPrecompiledFixture()
    {
        context = std::make_shared<ExecutiveContext>();
        paillierPrecompiled = std::make_shared<PaillierPrecompiled>();

        auto precompiledGasFactory = std::make_shared<dev::precompiled::PrecompiledGasFactory>(0);
        auto precompiledExecResultFactory =
            std::make_shared<dev::precompiled::PrecompiledExecResultFactory>();
        precompiledExecResultFactory->setPrecompiledGasFactory(precompiledGasFactory);
        paillierPrecompiled->setPrecompiledExecResultFactory(precompiledExecResultFactory);
    }

    ~PaillierPrecompiledFixture() {}

    ExecutiveContext::Ptr context;
    PaillierPrecompiled::Ptr paillierPrecompiled;
};

BOOST_FIXTURE_TEST_SUITE(test_PaillierPrecompiled, PaillierPrecompiledFixture)

BOOST_AUTO_TEST_CASE(TestHomAdd)
{
    std::string cipher1 =
        "0100C749FBB4A0A37F049DFFDAC1713D8861ED7ECE8474C1DD02DA069621B8C44C3B6F2FB80BECB0BCACBA5D1C"
        "1632E5F4CD1AFAEFF7A516BC7B834288E0A9AA9423176913BBB1269E34A66C29A4762E6DC2F143069BFA621560"
        "620746D48C1DADCD11E545E6E14923E5488AE8E38B6AC2ABF5FB39881AECAFA9540600F650FCB3BF4EB19BB94D"
        "1AACEEDE51F7DD5C50CE2A6D7506C1C3390A63AF157165D3927F987FE3AD8CFB5E93E889472D097B9232C95BB5"
        "874942DD29ADF2C2A58727A23707BBB7659E6E445A572872C8F0A0BAAA7B642056C895A60A0B991592486F2DFB"
        "242F3E8D8E09F9153ED69EF455F2C430D57B01759D87A21D81F14560E10241B4356E497AE2A738497F52B22EBC"
        "D9508417E78136634C516F608819E4A51DC0C3AB98C06383D6BC661A377D75BE6B9EB80BD98FFAA61FA61E9D53"
        "67EA89945942E2C9F946683633982BCA3E3D50CF6338F47F72F0C6A94598DF40A1BF153E87C24C46BE2905F41D"
        "2BCF711E37042BF063F36056176B7FE82E5312C68608781B9F1FF0E896350D7AC82CDD4E9BA90E106F8173FFA2"
        "DFA2A819E9E61F7F08C4A04333752EBDD7E7CBB5A7DCE2AFFE026FB5BE4DDE7E7BAE60A59D71BDE5E82F636D6C"
        "84DBB0622731E9BFF13030C53775A30E7AD81CE74F5A9717423AB810E361C9DE106817E1ED4F2CC3D38DCF8804"
        "7C611B74B769165195B04EE9D83D971A34ECC11F294F8FE0F9046CAFE8A81A62A181447D3AC93EFB9ABCB1ACEF"
        "0A95DB59FF2208E1AD1FE9B8EAD9CA945190FF8F932FF7A66F4603AFD9630585CD38BBAC761AAB48FC86D417CD"
        "5EFDFE02656E644F8565DA19DC9495BA36A47FDFD8BA55FACEB0B1799448996CD86B23A530F86226F5F28489D8"
        "D74E4DEE31C30FF28F9F5418636FB6A3127592AF04732A545DCFBAA60843400A14C27F3D80BE78DDE6D88B5D5D"
        "84B5FFED94C705C415EE8A434AB4FF35F41A043C8096982FC0D3FE3E60148542C33368DCDE252ACED58DC15615"
        "A09FA7E7B5994E3D4AC96631C0F71C1B33FE1EF1886CD941ADFA0E1225C4DCB29C0F031625C32C896B6926E508"
        "7413842BF9";
    std::string cipher2 =
        "0100C749FBB4A0A37F049DFFDAC1713D8861ED7ECE8474C1DD02DA069621B8C44C3B6F2FB80BECB0BCACBA5D1C"
        "1632E5F4CD1AFAEFF7A516BC7B834288E0A9AA9423176913BBB1269E34A66C29A4762E6DC2F143069BFA621560"
        "620746D48C1DADCD11E545E6E14923E5488AE8E38B6AC2ABF5FB39881AECAFA9540600F650FCB3BF4EB19BB94D"
        "1AACEEDE51F7DD5C50CE2A6D7506C1C3390A63AF157165D3927F987FE3AD8CFB5E93E889472D097B9232C95BB5"
        "874942DD29ADF2C2A58727A23707BBB7659E6E445A572872C8F0A0BAAA7B642056C895A60A0B991592486F2DFB"
        "242F3E8D8E09F9153ED69EF455F2C430D57B01759D87A21D81F14560E10241B4358FAE0D72FA484022FF0DB7C2"
        "DD4BC09D9E01AA345F3F7F3D648C4B7D071F0F31687128C237B4482C4DFE88416D7E48828585C958FC836EBDA4"
        "3C2B20A1D70E196250DADC7FF37A4B8E3A53C0ED933B0DA3CC835E657B1707462CCC3E3B7DCF32DEE9DAD46CEF"
        "E3FB336A6FFACBCF667D1BACE680274509A265B46F9625952CA295839FAD21EB15B6EDC318CB9FF4322ACA8EDA"
        "222B4A9D8E99A4FB5D0FBE2751D27843B57C69A512D98BBF775F064AFD7F6123C14195802F48C1FF48EA97CBCA"
        "6168C1497C0C86C04056D92FC1002FE24B4662F08D24404CB485E77D24570510732E2182F15E3D8FF334002501"
        "367A9A90A260CE546D1A0BCABCFF6227EA01442D8382B31F1E727C8C92443A9F408E001299374E15E286F69F76"
        "0EBE7A2C61C3E63C31EB4066B457236D4C3953F9E096D0B26E3436B330D446C92F31AB26CBC50F914CA8FCDB4D"
        "2674779DDC419F47E34E54DD2493121A8B854E030C8D8D0B40EBE164A287B684BEE3D94DBE788EFD7F2AE4E661"
        "B7A0908CE38E82B36305F15B8E0E977D25E98128F0BEFEAD5E3DC792464CF57A5E939C33CB815F78E857242FA9"
        "B1C3F9ABFC85206438CBA1861F31D66B57A1F9284706D5138E2F5D83EECA532D779BED7060B578609FA57AC16C"
        "7046DACA564E49EFDAF9ADA0C81DC25468AE84C07D9C38EDB1B8B84B5D18E7A33534C4A1070810D627037B1767"
        "A32BFC9A21";
    std::string cipher3 =
        "0100C749FBB4A0A37F049DFFDAC1713D8861ED7ECE8474C1DD02DA069621B8C44C3B6F2FB80BECB0BCACBA5D1C"
        "1632E5F4CD1AFAEFF7A516BC7B834288E0A9AA9423176913BBB1269E34A66C29A4762E6DC2F143069BFA621560"
        "620746D48C1DADCD11E545E6E14923E5488AE8E38B6AC2ABF5FB39881AECAFA9540600F650FCB3BF4EB19BB94D"
        "1AACEEDE51F7DD5C50CE2A6D7506C1C3390A63AF157165D3927F987FE3AD8CFB5E93E889472D097B9232C95BB5"
        "874942DD29ADF2C2A58727A23707BBB7659E6E445A572872C8F0A0BAAA7B642056C895A60A0B991592486F2DFB"
        "242F3E8D8E09F9153ED69EF455F2C430D57B01759D87A21D81F14560E10241B4355C2BD1010C0E12EF1BA4ED31"
        "A40607160C894E42CC2F366CB0F956E3ABDD7A0B2D07866EC82D33BE8817D06DECC3F100AABD25A2E014AE3522"
        "F6C57CB236186795EAEF3DF43524658224F46A478CB2B4566BE680A31F487FF493C1D5396FC0D669DD398DC429"
        "DA0B9FA85A79933DE2A2A5920B89AF075023EA3364121C5E9AD08019A310880BCC4ADF180E73BB12C3AA98F86C"
        "82AB362744F93ED94078CFB3A47DBB30B32A616438E4EA5420A925E400658957F8452576712F7F0DCDFDCEFA27"
        "76223E53CD76E0DCE6F73EC9B0890202386E0FED91E813B7EEAA634B3B0E3B19378DCC3340F21313EFCA5CF632"
        "32F22D1110F70D3E90737DF71A278856C501B01DA4231FD39006BE37B627E2CA3251B15D5B024C03D8D65F7CC8"
        "185EC65B985AE052F2E4F3ABEFEFBEC1607C264F2BDC385C3420B3A6E054B6787DC1E73806C494C947366ECC8B"
        "767920959488C969A14A77CB5885264B34BA4F0A6B0F23BCB95B2EE31859D1C0C003D6C09F6133DF7780D6588C"
        "E3AEE8DD777C940EF753195D76624F6377ECB5F7DC9783780CC27F4C2624E00360AFBB084F274DB0C3365AED19"
        "1E2923D76CEE5171043E4D9D25BC0257FEBF113A9868494CB6BF6C8E5CBADE5478B65806ADB3825F1537D19DE0"
        "FE34667819DCC1893A8B6F5C1C37AB54EAA2D012D21CB6BF4DC88004FF2EF9EE836F3CC73F0D4DB13D1B5B8992"
        "C0D1C97483";
    dev::eth::ContractABI abi;
    bytes in = abi.abiIn("paillierAdd(string,string)", cipher1, cipher2);
    auto callResult = paillierPrecompiled->call(context, bytesConstRef(&in));
    bytes out = callResult->execResult();
    std::string result;
    abi.abiOut(bytesConstRef(&out), result);
    BOOST_TEST(result == cipher3);
}

BOOST_AUTO_TEST_CASE(ErrorFunc)
{
    dev::eth::ContractABI abi;
    bytes in = abi.abiIn("add(string,string)", std::string("2AE3FFE2"), std::string("2AE3FFE2"));
    auto callResult = paillierPrecompiled->call(context, bytesConstRef(&in));
    bytes out = callResult->execResult();
    s256 count = 1;
    abi.abiOut(bytesConstRef(&out), count);
    if (g_BCOSConfig.version() > RC2_VERSION)
    {
        BOOST_TEST(count == CODE_UNKNOW_FUNCTION_CALL);
    }
    else
    {
        BOOST_TEST(count == -CODE_UNKNOW_FUNCTION_CALL);
    }
}

BOOST_AUTO_TEST_CASE(InvalidInputs)
{
    // situation1
    dev::eth::ContractABI abi;
    bytes in = abi.abiIn(
        "paillierAdd(string,string)", std::string("2AE3FFE2"), std::string("2AE3FFE22AE3FFE2"));
    auto callResult = paillierPrecompiled->call(context, bytesConstRef(&in));
    bytes out = callResult->execResult();
    s256 count = 1;
    abi.abiOut(bytesConstRef(&out), count);
    if (g_BCOSConfig.version() > RC2_VERSION)
    {
        BOOST_TEST(count == CODE_INVALID_CIPHERS);
    }
    else
    {
        BOOST_TEST(count == -CODE_INVALID_CIPHERS);
    }

    // situation2
    in = abi.abiIn("paillierAdd(string,string)", std::string("1111FFE22AE3FFE2"),
        std::string("2AE3FFE22AE3FFE2"));
    callResult = paillierPrecompiled->call(context, bytesConstRef(&in));
    out = callResult->execResult();
    count = 1;
    abi.abiOut(bytesConstRef(&out), count);
    if (g_BCOSConfig.version() > RC2_VERSION)
    {
        BOOST_TEST(count == CODE_INVALID_CIPHERS);
    }
    else
    {
        BOOST_TEST(count == -CODE_INVALID_CIPHERS);
    }

    // situation3
    std::string cipher3 =
        "0070932D5857D9FCFD8CEEDB7593F6EAF8CD192447C6CA2F5AAA27971A19CCE957CC5E30AE56FE79DD7EC125C4"
        "AC9DE23884C58F229D1A08B56DD6C4DA8844DDFBA51AE81DC45E5F280B65BC69404370E6617DB7CEF45C12912D"
        "B6FE0709B0FFF8008B13498516BAD7F6C7453ED7C7DD0D75283A3E1D8D21D453C8F159B82A96FEBF3502ADC325"
        "CEC5750DB8029E327642E75C03A30628525E05CF0D272536432977D3981E550ADC1B2A2ACCAEBB039B1F62F1D2"
        "359A7B1D9D4B5EA6854A417FD4695A81E0D7E29319888507EADC55FC49BA2B76CF86559C770D3DD06A669CE3AF"
        "248534C85289FAE7509DE40C0E8A55E2D83F5552C99679414D4C433313C7EB296CDD0037189B00C6E9DBC33A95"
        "95A222DB990A3B7F7D6658DD532251BB160FF0C23FE691AD3240BE7A2484722EFCBB8AE10DDB7CC719B9076E39"
        "4C856800539EB71D3B82FAD9DA4529D7547BAA2EA258357A3EFE5B8B0F4F0FBD36FF0D3DD25213E78AD8319886"
        "5DFBC7B818C1D2B561E1B00F1D81B1986B7B8C72A629BBF67F5D";
    in = abi.abiIn("paillierAdd(string,string)", cipher3, cipher3);
    callResult = paillierPrecompiled->call(context, bytesConstRef(&in));
    out = callResult->execResult();
    count = 1;
    abi.abiOut(bytesConstRef(&out), count);
    if (g_BCOSConfig.version() > RC2_VERSION)
    {
        BOOST_TEST(count == CODE_INVALID_CIPHERS);
    }
    else
    {
        BOOST_TEST(count == -CODE_INVALID_CIPHERS);
    }

    // situation4
    std::string cipher4 =
        "0080932D5857D9FCFD8CEEDB7593F6EAF8CD192447C6CA2F5AAA27971A19CCE957CC5E30AE56FE79DD7EC125C4"
        "A2C6A2EF9D186A66D5FCFBC3B55D43B9E5D428C07EB4D2AE3CC98FC1CF24BFD5BCD266A924810C7C48F6EAA81C"
        "B6FE0709B0FFF8008B13498516BAD7F6C7453ED7C7DD0D75283A3E1D8D21D453C8F159B82A96FEBF3502ADC325"
        "CEC5750DB8029E327642E75C03A30628525E05CF0D272536432977D3981E550ADC1B2A2ACCAEBB039B1F62F1D2"
        "359A7B1D9D4B5EA6854A417FD4695A81E0D7E29319888507EADC55FC49BA2B76CF86559C770D3DD06A669CE3AF"
        "248534C85289FAE7509DE40C0E8A55E2D83F5552C99679414D4C433313C7EB296CDD0037189B00C6E9DBC33A95"
        "95A222DB990A3B7F7D6658DD532251BB160FF0C23FE691AD3240BE7A2484722EFCBB8AE10DDB7CC719B9076E39"
        "4C856800539EB71D3B82FAD9DA4529D7547BAA2EA258357A3EFE5B8B0F4F0FBD36FF0D3DD25213E78AD8319888"
        "CEC5750DB8029E327642E75C03A30628525E05CF0D272536432977D3981E550ADC1B2A2ACCAEBB039B1F62F1D2"
        "359A7B1D9D4B5EA6854A417FD4695A81E0D7E29319888507EADC55FC49BA2B76CF86559C770D3DD06A669CE3AF"
        "248534C85289FAE7509DE40C0E8A55E2D83F5552C99679414D4C433313C7EB296CDD0037189B00C6E9DBC33A95"
        "95A222DB990A3B7F7D6658DD532251BB160FF0C23FE691AD3240BE7A2484722EFCBB8AE10DDB7CC719B9076E39"
        "4C856800539EB71D3B82FAD9DA4529D7547BAA2EA258357A3EFE5B8B0F4F0FBD36FF0D3DD25213E78AD831988";
    in = abi.abiIn("paillierAdd(string,string)", cipher4, cipher4);
    callResult = paillierPrecompiled->call(context, bytesConstRef(&in));
    out = callResult->execResult();
    count = 1;
    abi.abiOut(bytesConstRef(&out), count);
    if (g_BCOSConfig.version() > RC2_VERSION)
    {
        BOOST_TEST(count == CODE_INVALID_CIPHERS);
    }
    else
    {
        BOOST_TEST(count == -CODE_INVALID_CIPHERS);
    }

    // situation5
    std::string cipher51 =
        "0080932D5857D9FCFD8CEEDB7593F6EAF8CD192447C6CA2F5AAA27971A19CCE957CC5E30AE56FE79DD7EC125C4"
        "AC9DE23884C58F229D1A08B56DD6C4DA8844DDFBA51AE81DC45E5F280B65BC69404370E6617DB7CEF45C12912D"
        "AC9DE23884C58F229D1A08B56DD6C4DA8844DDFBA51AE81DC45E5F280B65BC69404370E6617DB7CEF45C12912D"
        "CEC5750DB8029E327642E75C03A30628525E05CF0D272536432977D3981E550ADC1B2A2ACCAEBB039B1F62F1D2"
        "359A7B1D9D4B5EA6854A417FD4695A81E0D7E29319888507EADC55FC49BA2B76CF86559C770D3DD06A669CE3AF"
        "248534C85289FAE7509DE40C0E8A55E2D83F5552C99679414D4C433313C7EB296CDD0037189B00C6E9DBC33A95"
        "95A222DB990A3B7F7D6658DD532251BB160FF0C23FE691AD3240BE7A2484722EFCBB8AE10DDB7CC719B9076E39"
        "4C856800539EB71D3B82FAD9DA4529D7547BAA2EA258357A3EFE5B8B0F4F0FBD36FF0D3DD25213E78AD8319886"
        "5DFBC7B818C1D2B561E1B00F1D81B1986B7B8C72A629BBF67F5D";
    std::string cipher52 =
        "0080932D5857D9FCFD8CEEDB7593F6EAF8CD192447C6CA2F5AAA27971A19CCE957CC5E30AE56FE79DD7EC125C4"
        "AC9DE23884C58F229D1A08B56DD6C4DA8844DDFBA51AE81DC45E5F280B65BC69404370E6617DB7CEF45C12912D"
        "B6FE0709B0FFF8008B13498516BAD7F6C7453ED7C7DD0D75283A3E1D8D21D453C8F159B82A96FEBF3502ADC325"
        "CEC5750DB8029E327642E75C03A30628525E05CF0D272536432977D3981E550ADC1B2A2ACCAEBB039B1F62F1D2"
        "359A7B1D9D4B5EA6854A417FD4695A81E0D7E29319888507EADC55FC49BA2B76CF86559C770D3DD06A669CE3AF"
        "248534C85289FAE7509DE40C0E8A55E2D83F5552C99679414D4C433313C7EB296CDD0037189B00C6E9DBC33A95"
        "95A222DB990A3B7F7D6658DD532251BB160FF0C23FE691AD3240BE7A2484722EFCBB8AE10DDB7CC719B9076E39"
        "4C856800539EB71D3B82FAD9DA4529D7547BAA2EA258357A3EFE5B8B0F4F0FBD36FF0D3DD25213E78AD8319886"
        "5DFBC7B818C1D2B561E1B00F1D81B1986B7B8C72A629BBF67F5D";
    in = abi.abiIn("paillierAdd(string,string)", cipher51, cipher52);
    callResult = paillierPrecompiled->call(context, bytesConstRef(&in));
    out = callResult->execResult();
    count = 1;
    abi.abiOut(bytesConstRef(&out), count);
    if (g_BCOSConfig.version() > RC2_VERSION)
    {
        BOOST_TEST(count == CODE_INVALID_CIPHERS);
    }
    else
    {
        BOOST_TEST(count == -CODE_INVALID_CIPHERS);
    }
}

BOOST_AUTO_TEST_SUITE_END()

}  // namespace test_PaillierPrecompiled
